package com.unitd.modules.gen.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.unitd.frame.comm.utils.BeanUtils;
import com.unitd.frame.comm.utils.DateUtils;
import com.unitd.frame.comm.utils.StringUtils;
import com.unitd.frame.mybatis.core.dao.ICrudDao;
import com.unitd.frame.mybatis.core.service.impl.CrudServiceImpl;
import com.unitd.modules.gen.dao.IGenSchemeDao;
import com.unitd.modules.gen.entity.*;
import com.unitd.modules.gen.service.IGenSchemeService;
import com.unitd.modules.gen.service.IGenTableColumnService;
import com.unitd.modules.gen.service.IGenTableService;
import com.unitd.modules.gen.util.GenUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @desc 生成方案Service
 * @filename GenSchemeService.java
 * @copyright www.unitdtech.com
 * @author Hudan
 * @version 1.0
 * @date 2017-04-27
 */
@Service("genSchemeService")
public class GenSchemeServiceImpl extends CrudServiceImpl<GenScheme, String> implements IGenSchemeService {

	@Autowired
	private IGenSchemeDao genSchemeDao;
	@Autowired
	private IGenTableService genTableService;
	@Autowired
	private IGenTableColumnService genTableColumnService;

	/**
	 * @desc 定义成抽象方法, 由子类实现, 完成dao的注入
	 * @return GenericDao实现类
	 */
	@Override
	public ICrudDao<GenScheme, String> getDao() {
		return genSchemeDao;
	}

	/**
	 * @desc 获取单条数据
	 * @param id 主键ID
	 * @return
	 */
	@Override
	public GenScheme findBy(String id) {
		GenScheme genScheme = genSchemeDao.findBy(id);
		if(genScheme == null) return new GenScheme();
		return genScheme;
	}

	/**
	 * @desc 查询数据列表，如果需要分页，请设置分页对象，如：entity.setPage(new Page<T>());
	 * @param entity 查询参数对象
	 * @return List<Model>
	 */
	@Override
	public List<GenScheme> findListBy(GenScheme entity) {
		return genSchemeDao.findListBy(entity);
	}

	/**
	 * @desc 查询所有数据列表
	 * @param entity 查询参数对象
	 * @return List<Model>
	 */
	@Override
	public List<GenScheme> findAllData(GenScheme entity) {
		return genSchemeDao.findAllData(entity);
	}

	/**
	 * @desc 进行逻辑删除处理
	 * @param genScheme 生成方案对象
	 * @return
	 */
	@Override
	public int deleteByDelFlag(GenScheme genScheme){
		return genSchemeDao.deleteByDelFlag(genScheme);
	}

	/**
	 * @desc 根据主键ID获取详情信息,并将获取的信息在详情页展示转到信息列表页
	 * @param genSchemeId 生成方案主键ID
	 * @return
	 */
	@Override
	public Map<String, Object> toEdit(String genSchemeId) {
		Map<String, Object> dataMap = Maps.newConcurrentMap();

		// 根据ID获取表生成方案详情
		GenScheme genScheme = findBy(genSchemeId);
		if (StringUtils.isBlank(genScheme.getPackageName())) {
			genScheme.setPackageName("com.unitd.modules");
		}
		if (StringUtils.isBlank(genScheme.getFunctionAuthor())){
			genScheme.setFunctionAuthor("Hudan");
		}

		// 根据方案中的需要生成的表名获取对应的表注释信息
		String tableComments = genTableService.getTableCommentsByTableNames(genScheme.getGenTableNames());

		// 获取需要进行自动代码生成的数据库表列表
		List<GenTable> genTables = genTableService.findAllData(new GenTable());

		dataMap.put("genScheme", genScheme);
		dataMap.put("genTableComments", tableComments);
		dataMap.put("config", GenUtils.getConfig());
		dataMap.put("tableList", genTables);
		return dataMap;
	}

	/**
	 * @desc 保存/更新生成方案信息持久化对象
	 * @param genScheme 生成方案信息
	 * @param userId 操作人
	 * @return
	 */
	@Override
	@Transactional(rollbackFor={RuntimeException.class, Exception.class, Throwable.class})
	public String doEdit(GenScheme genScheme, String userId) {
		int result;

		if (!StringUtils.isNull(genScheme.getId())) {
			genScheme.setUpdateBy(userId);
			genScheme.setUpdateDate(DateUtils.formatDate(new Date(), DateUtils.TIMESTAMP_PATTERN));
			genScheme.preUpdate();
			result = genSchemeDao.updateByPrimaryKeySelective(genScheme);
		} else {
			genScheme.setCreateBy(userId);
			genScheme.setCreateDate(DateUtils.formatDate(new Date(), DateUtils.TIMESTAMP_PATTERN));
			genScheme.preInsert();
			result = genSchemeDao.insertSelective(genScheme);
		}

		// 生成代码
		if ("1".equals(genScheme.getFlag())) {
			return generateCode(genScheme);
		}
		return String.valueOf(result);
	}

	/**
	 * @desc 处理生成代码逻辑
	 * @param genScheme 代码生成方案对象
	 * @return
	 */
	private String generateCode(GenScheme genScheme)  {
		try {
			// 获取所有代码模板
			GenConfig config = GenUtils.getConfig();

			// 根据前端选择的需要生成的数据表进行分组
			List<String> tableNames = StringUtils.toList(genScheme.getGenTableNames(), ",");
			String className; 				// 表对应的Java类名

			for(String tableName : tableNames) {
				// 根据数据库表名,查询主表及字段列
				GenTable genTable = genTableService.findByTableName(tableName);
				if(BeanUtils.isNull(genTable)) continue;

				className = genTable.getClassName();
				List<GenTableColumn> tableColumns = genTableColumnService.findListBy(new GenTableColumn(new GenTable(genTable.getId())));

				// 根据配置表及对应的列和生成方案信息,生成对应的代码文件
				generateToFile(config, genScheme, genTable, tableColumns);

				// 如果当前配置表对象中选择了创建FO表,则需要将FO表对应的代码也生成
				if("1".equals(genTable.getCreateFo())) {
					genTable.setTableName(getTableNameByTp(tableName, "_FO"));
					genTable.setClassName(getClassNameByTp(className, "Fo"));
					generateToFile(config, genScheme, genTable, tableColumns);
				}
				// 如果当前配置表对象中选择了创建AR表,则需要将AR表对应的代码也生成
				if("1".equals(genTable.getCreateAr())) {
					genTable.setTableName(getTableNameByTp(tableName, "_AR"));
					genTable.setClassName(getClassNameByTp(className, "Ar"));
					generateToFile(config, genScheme, genTable, tableColumns);
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
		return "success";
	}

	/**
	 * @desc 根据配置表及对应的列和生成方案信息,生成对应的代码文件
	 * @param config 模板配置对象
	 * @param genScheme 生成方案对象
	 * @param genTable 生成配置表对象
	 * @param tableColumns 生成配置表的列对象
	 */
	private void generateToFile(GenConfig config, GenScheme genScheme, GenTable genTable, List<GenTableColumn> tableColumns) {

		// 新的数据库表的列集合
		List<GenTableColumn> transColumns = Lists.newArrayList();

		for(GenTableColumn column : tableColumns) {
			if ("1".equals(column.getIsPk())) {
				genTable.setPk(column); 											// 适用于仪表只有一个主键列
			} else {
				column.setIsPk("0");
			}

			// 对于自定义的数据类型的列,需要重新根据其类型,在往list中加入一条数据
			if (GenUtils.checkBaseJavaType(config.getBaseJavaTypeList(), column.getJavaType()) &&
					!column.getBaseJavaType().equals(column.getJavaType()) &&
					!"updateBy".equals(column.getBaseJavaField()) &&
					!"createBy".equals(column.getBaseJavaField())) {
				transColumns.add(column);
			}
		}
		genTable.setColumnList(tableColumns);
		genTable.setTransColumnList(transColumns);

		// 获取模板列表
		List<GenTemplate> templateList = GenUtils.getTemplateList(config, genScheme.getCategory(), false);
//		List<GenTemplate> childTableTemplateList = GenUtils.getTemplateList(config, genScheme.getCategory(), true);

//		// 如果有子表模板，则需要获取子表列表
//		if (childTableTemplateList.size() > 0) {
//			GenTable parentTable = new GenTable();
//			parentTable.setParentTable(genTable.getTableName());
//			genTable.setChildList(genTableDao.findListBy(parentTable));
//		}

//		// 生成子表模板代码
//		for (GenTable childTable : genTable.getChildList()) {
//			childTable.setParent(genTable);
//			childTable.setColumnList(genTableColumnDao.findListBy(new GenTableColumn(new GenTable(childTable.getId()))));
//			genScheme.setGenTable(childTable);
//			Map<String, Object> childTableModel = GenUtils.getDataModel(genScheme);
//			for (GenTemplate tpl : childTableTemplateList) {
//				result.append(GenUtils.generateToFile(tpl, childTableModel, genScheme.getReplaceFile()));
//			}
//		}

		// 生成主表模板代码
		genScheme.setTable(genTable);
		Map<String, Object> model = GenUtils.getDataModel(genScheme);
		model.put("pk", genTable.getPk()); 					// 表主键类型信息
		model.put("tableName", genScheme.getTable().getTableName());
		model.put("tableComment", StringEscapeUtils.unescapeHtml4(genScheme.getTable().getComments()));
		model.put("className", StringUtils.uncapitalize(genScheme.getTable().getClassName()));
		model.put("ClassName", StringUtils.capitalize(genScheme.getTable().getClassName()));

		for (GenTemplate tpl : templateList) {
			GenUtils.generateToFile(tpl, model, genScheme.getReplaceFile());
		}
	}

	/**
	 * @desc 根据原表名获取对应的fo/ar表名称
	 * @param tableName 原表名称
	 * @param suffix 表名后缀(FO/AR)
	 * @return
	 */
	private String getTableNameByTp(String tableName, String suffix) {
		if(tableName.toUpperCase().endsWith("_TP")) {
			return tableName.substring(0, tableName.lastIndexOf("_TP")) + suffix.toUpperCase();
		} else {
			return (tableName + suffix).toUpperCase();
		}
	}

	/**
	 * @desc 根据原类名获取对应的fo/ar类名名称
	 * @param tableName 原类名称
	 * @param suffix 类名后缀(Fo/Ar)
	 * @return
	 */
	private String getClassNameByTp(String tableName, String suffix) {
		if(tableName.endsWith("Tp")) {
			return tableName.substring(0, tableName.lastIndexOf("Tp")) + suffix;
		} else {
			return tableName + suffix;
		}
	}

	public static void main(String[] args) {

		String str1 = "Bopb_TP";
		System.out.println(str1.substring(0, str1.lastIndexOf("_TP"))+"XX");
		String str = "Bopb";
		System.out.println(str.substring(0, str.lastIndexOf("Tp"))+"Fo");
	}
}